package com.bytetool.agent.method;

import com.bytetool.agent.producer.LoggerProducer;
import com.bytetool.common.entity.PerformanceInfo;
import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.NotFoundException;

/**
 * @author zouhuixing
 * @date 2024/3/31
 */
public class PerformanceModifyMethod {

    public static void monitorMethodPerformance(CtClass ctClass, CtMethod ctMethod) throws CannotCompileException, NotFoundException {
        String changedMethodName = ctMethod.getName();
        String copyMethodName = "_do" + changedMethodName;
        CtMethod copyMethod = CtNewMethod.copy(ctMethod, changedMethodName, ctClass, null);
        copyMethod.setName(copyMethodName);
        ctClass.addMethod(copyMethod);
        //构造原始方法的方法体
        ctMethod.setBody(buildMethodForPerformance(ctMethod, copyMethodName));
    }

    private static String buildMethodForPerformance(CtMethod method, String newMethodName) throws NotFoundException {
        StringBuffer body = new StringBuffer();
        String methodName = method.getLongName();
        body.append("{");
        body.append("    com.bytetool.agent.method.PerformanceModifyMethod.startPerformance(\"" + methodName + "\");");
        body.append("    try{");
        body.append("        %s " + newMethodName + "($$);");
        body.append("    }finally{");
        body.append("        com.bytetool.agent.method.PerformanceModifyMethod.sendPerformance( \""
                + methodName + "\" , System.currentTimeMillis());");
        body.append("    }");
        body.append("}");
        String bodyContext = body.toString();
        if ("void".equals(method.getReturnType().getName())) {
            return String.format(bodyContext, "");
        } else {
            return String.format(bodyContext, "return");
        }
    }

    /**
     * 反射调用
     *
     * @param methodName
     * @param endTime
     */
    @Deprecated
    public static void sendPerformance(String methodName, long endTime) {
        PerformanceInfo info = TraceInfoUtil.getPerformanceInfo();
        info.setStartTime(endTime);
        info.setSpend(endTime - info.getStartTime());
        info.setMethodName(methodName);
        try {
            LoggerProducer.push(info);
        } catch (Exception e) {

        }

    }

    @Deprecated
    public static void startPerformance(String methodName) {

        TraceInfoUtil.initCurrentPerformanceInfo(methodName);
    }

}
